﻿using System;
using System.Collections.Generic;
using System.Text;

namespace TTLL.Asm
{
    internal class AST
    {
        static string NextColonInLine(IList<Word.Word> words, ref int pos)
        {

            if (words.Count <= pos)
                return null;
            if (words[pos].wordtype == Word.WordType.NewLine)
                return null;
            for (var i = pos; i < words.Count; i++)
            {
                if (words[i].wordtype == Word.WordType.Space || words[i].wordtype == Word.WordType.Comment)
                    continue;
                if (words[i].wordtype == Word.WordType.Colon)
                {
                    pos = i + 1;
                    return words[i].text;
                }
                else
                {
                    return null;
                }
            }
            return null;
        }
        static string NextWordInLine(IList<Word.Word> words, ref int pos)
        {

            if (words.Count <= pos)
                return null;
            if (words[pos].wordtype == Word.WordType.NewLine)
                return null;
            for (var i = pos; i < words.Count; i++)
            {
                if (words[i].wordtype == Word.WordType.Space || words[i].wordtype == Word.WordType.Comment)
                    continue;
                if (words[i].wordtype == Word.WordType.Word)
                {
                    pos = i + 1;
                    return words[i].text;
                }
                else
                {
                    return null;
                }
            }
            return null;
        }
        static string NextWordInLines(IList<Word.Word> words, ref int pos)
        {
            if (words.Count <= pos)
                return null;
            for (var i = pos; i < words.Count; i++)
            {
                if (words[i].wordtype == Word.WordType.NewLine)
                    continue;
                if (words[i].wordtype == Word.WordType.Space || words[i].wordtype == Word.WordType.Comment)
                    continue;
                if (words[i].wordtype == Word.WordType.Word)
                {
                    pos = i + 1;
                    return words[i].text;
                }
                else
                {
                    throw new Exception("error step");
                }
            }
            return null;

        }
        static string NextBraceInLines(IList<Word.Word> words, ref int pos)
        {
            if (words.Count <= pos)
                return null;
            for (var i = pos; i < words.Count; i++)
            {
                if (words[i].wordtype == Word.WordType.NewLine)
                    continue;
                if (words[i].wordtype == Word.WordType.Space || words[i].wordtype == Word.WordType.Comment)
                    continue;
                if (words[i].wordtype == Word.WordType.Braces)
                {
                    pos = i + 1;
                    return words[i].text;
                }
                else
                {
                    throw new Exception("error step");
                }
            }
            return null;

        }
        static bool TryGetNextBraceInLines(IList<Word.Word> words, ref int pos, out string text)
        {
            if (words.Count <= pos)
            {
                text = null;
                return false;
            }
            for (var i = pos; i < words.Count; i++)
            {
                if (words[i].wordtype == Word.WordType.NewLine)
                    continue;
                if (words[i].wordtype == Word.WordType.Space || words[i].wordtype == Word.WordType.Comment)
                    continue;
                if (words[i].wordtype == Word.WordType.Braces)
                {
                    pos = i + 1;
                    text = words[i].text;
                    return true;
                }
                else
                {
                    text = null;
                    return false;
                }
            }
            text = null;
            return false;

        }
        static int BraceEnd(IList<Word.Word> words, int pos)
        {
            string endtag = "";

            string begintag = words[pos].text;
            if (begintag == "[") endtag = "]";
            else if (begintag == "(") endtag = ")";
            else if (begintag == "{") endtag = "}";
            else throw new Exception("error tag");
            var deep = 0;
            for (var i = pos; i < words.Count; i++)
            {
                if (words[i].text == begintag)
                    deep++;
                if (words[i].text == endtag)
                {
                    deep--;
                    if (deep == 0)
                    {
                        return i;
                    }
                }
            }
            throw new Exception("not end brace.");
        }


        internal class AstDoc
        {
            public List<INode> nodes = new List<INode>();
            public static AstDoc Parse(string text)
            {
                AstDoc doc = new AstDoc();
                var words = TTLL.Asm.Word.WordScanner.Scan(text);
                List<Attribute> attrs = new List<Attribute>();
                for (var i = 0; i < words.Count; i++)
                {
                    //const comment
                    //attribute [head]
                    //function
                    //struct
                    var word = words[i];
                    var type = word.wordtype;
                    switch (type)
                    {
                        case Word.WordType.None:
                        case Word.WordType.Space:
                        case Word.WordType.NewLine:
                            continue;
                        case Word.WordType.Comment:
                            {
                                var comment = new Comment();
                                comment.text = word.text;
                                doc.nodes.Add(comment);
                            }
                            break;
                        case Word.WordType.Braces:
                            {
                                if (word.text == "[")
                                {
                                    attrs.Add(Attribute.Parse(words, ref i));
                                    continue;
                                }
                                else
                                {
                                    throw new Exception("error step");
                                }
                            }
                        case Word.WordType.Word:
                            {
                                if (word.text == "const")
                                {
                                    if (attrs.Count > 0)
                                        throw new Exception("error attr s");
                                    doc.nodes.Add(ConstAst.Parse(words, ref i));
                                    continue;
                                }
                                if (word.text == "function")
                                {
                                    var func = Function.Parse(words, ref i);
                                    foreach (var attr in attrs)
                                    {
                                        func.head.Add(attr);
                                    }
                                    attrs.Clear();
                                    doc.nodes.Add(func);
                                    continue;
                                }
                                if (word.text == "struct")
                                {
                                    var _st = Struct.Parse(words, ref i);
                                    foreach (var attr in attrs)
                                    {
                                        _st.head.Add(attr);
                                    }
                                    attrs.Clear();
                                    doc.nodes.Add(_st);
                                    continue;
                                }
                            }
                            break;
                        default:
                            throw new Exception("error step");
                    }
                }
                return doc;
            }
        }
        internal interface INode
        {

        }
        internal class Comment : INode
        {
            public string text;
        }
        internal class ConstAst : INode
        {
            public string type;
            public string name;
            public string value;
            public static ConstAst Parse(IList<Word.Word> words, ref int pos)
            {
                ConstAst _c = new ConstAst();
                pos++;
                _c.type = NextWordInLine(words, ref pos);
                _c.name = NextWordInLine(words, ref pos);
                var eq = NextWordInLine(words, ref pos);
                var value = NextWordInLine(words, ref pos);
                var end = NextWordInLine(words, ref pos);
                if (end != null)
                {
                    throw new Exception("error step in const");

                }
                if (eq == "=")
                {
                    if (value == null)
                        throw new Exception("error const define.");
                    _c.value = value;
                }
                return _c;
            }
        }
        internal class TypeValue : INode
        {
            public string type;
            public string name;
            public string value;
            public static TypeValue Parse(IList<Word.Word> words, ref int pos)
            {
                var v = new TypeValue();
                v.type = NextWordInLine(words, ref pos);
                v.name = NextWordInLine(words, ref pos);
                var eq = NextWordInLine(words, ref pos);
                var value = NextWordInLine(words, ref pos);
                if (eq == "=")
                {
                    if (value != null)
                        v.value = value;
                    else
                        throw new Exception("error format.");
                }
                return v;
            }
        }
        internal class Value : INode
        {
            public string name;
            public string value;
        }
        internal class Struct : INode
        {
            public string name;
            public List<INode> head = new List<INode>();//头上主要是attribute 和注释
            public List<INode> members = new List<INode>();
            public string comment;
            public static Struct Parse(IList<Word.Word> words, ref int pos)
            {
                Struct _s = new Struct();
                pos++;
                _s.name = NextWordInLines(words, ref pos);
                var blockbegin = NextBraceInLines(words, ref pos);
                if (blockbegin != "{")
                    throw new Exception("error brace.");
                var posend = BraceEnd(words, pos - 1);
                while (pos < posend)
                {
                    //member loop
                    if (words[pos].wordtype == Word.WordType.Space || words[pos].wordtype == Word.WordType.NewLine)
                    {
                        pos++;
                        continue;
                    }
                    else if (words[pos].wordtype == Word.WordType.Comment)
                    {
                        _s.members.Add(new Comment() { text = words[pos].text });
                        pos++;
                        continue;
                    }
                    else if (words[pos].wordtype == Word.WordType.Word)
                    {
                        TypeValue type = new TypeValue();
                        type.type = NextWordInLine(words, ref pos);
                        type.name = NextWordInLine(words, ref pos);
                        var eq = NextWordInLine(words, ref pos);
                        var value = NextWordInLine(words, ref pos);
                        var end = NextWordInLine(words, ref pos);
                        if (end != null)
                        {
                            throw new Exception("error step in const");
                        }
                        if (eq == "=")
                        {
                            if (value == null)
                                throw new Exception("error const define.");
                            type.value = value;
                        }
                        _s.members.Add(type);
                    }
                    else
                    {
                        throw new Exception("what the fuck.");
                    }


                }
                pos = posend + 1;
                return _s;
            }
        }
        internal class Attribute : INode
        {
            public string name;
            public List<Value> values = new List<Value>();
            public static Attribute Parse(IList<Word.Word> words, ref int pos)
            {
                Attribute attr = new Attribute();
                var posend = BraceEnd(words, pos);
                pos++;
                if (pos < posend)
                {
                    attr.name = NextWordInLine(words, ref pos);
                    var left = NextBraceInLines(words, ref pos);
                    if (pos < posend && left == "(")
                    {//have (
                        attr.values = new List<Value>();
                        var right = BraceEnd(words, pos - 1);
                        if (right < posend)
                        {
                            for (var i = pos; i < right; i++)
                            {
                                //values loop;
                                var v = new Value();
                                v.name = NextWordInLine(words, ref pos);
                                var eq = NextWordInLine(words, ref pos);
                                var value = NextWordInLine(words, ref pos);
                                if (eq == "=")
                                {
                                    if (value != null)
                                        v.value = value;
                                    else
                                        throw new Exception("error format.");
                                }
                                else
                                {
                                    v.value = v.name;
                                    v.name = null;
                                }
                                attr.values.Add(v);
                                var end = NextWordInLine(words, ref pos);
                                if (end == null)
                                    break;
                            }
                        }
                    }

                }
                pos = posend + 1;
                return attr;
            }
        }
        internal class Body : INode
        {
            public List<INode> body = new List<INode>();
            public static Body Parse(IList<Word.Word> words, int pos, int posend)
            {
                Body body = new Body();
                while (pos < posend)
                {
                    if (words[pos].wordtype == Word.WordType.Space || words[pos].wordtype == Word.WordType.NewLine)
                    {
                        pos++;
                        continue;
                    }
                    else if (words[pos].wordtype == Word.WordType.Comment)
                    {
                        body.body.Add(new Comment() { text = words[pos].text });
                        pos++;
                        continue;
                    }
                    // if 裏面 是一變量 ，優化的事情讓編譯器去考慮就可以了
                    // 重新思考一下方針是容易JIT，可以被優化，二進制要容易
                    // 不使用邏輯運算符，用位運算符即可
                    // if(cond) block
                    // ifnot block
                    // block

                    else if (words[pos].wordtype == Word.WordType.Word)
                    {
                        var pos2 = pos+1;
                        var colon = AST.NextColonInLine(words, ref pos2);
                        if (colon == ":")//namedblock
                        {
                            var name = words[pos].text;
                            pos = pos2;
                            var block = Instruction.ParseBlock(words, ref pos);
                            block.block_label = name;
                            body.body.Add(block);
                        }
                        else if (words[pos].text.ToLower() == "define")
                        {
                            pos++;
                            body.body.Add(TypeValue.Parse(words, ref pos));
                        }
                        else if (words[pos].text.ToLower() == "if")
                        {
                            pos++;
                            body.body.Add(Instruction.ParseIf(words, ref pos));
                        }
                        else
                        {
                            body.body.Add(Instruction.Parse(words, ref pos));
                        }
                    }
                    else if (words[pos].wordtype == Word.WordType.Braces && words[pos].text == "{")
                    {
                        body.body.Add(Instruction.ParseBlock(words, ref pos));
                    }
                }
                return body;
            }
        }
        internal class Function : INode
        {
            public string returntype;
            public string name;
            public List<INode> head = new List<INode>();//头上主要是attribute 和注释
            public List<TypeValue> _params = new List<TypeValue>();
            public Body body;//Instruction 和 注释
            public string comment;
            public static Function Parse(IList<Word.Word> words, ref int pos)
            {
                Function func = new Function();
                pos++;
                func.returntype = NextWordInLine(words, ref pos);
                func.name = NextWordInLine(words, ref pos);
                var left = NextBraceInLines(words, ref pos);
                if (left == "(")
                {//have (
                    var right = BraceEnd(words, pos - 1);
                    if (right < words.Count)
                    {
                        while (pos < right)
                        {
                            //values loop;
                            var v = new TypeValue();
                            v.type = NextWordInLine(words, ref pos);
                            v.name = NextWordInLine(words, ref pos);
                            var eq = NextWordInLine(words, ref pos);
                            var value = NextWordInLine(words, ref pos);
                            if (eq == "=")
                            {
                                if (value != null)
                                    v.value = value;
                                else
                                    throw new Exception("error format.");
                            }
                            func._params.Add(v);
                            var end = NextWordInLine(words, ref pos);
                            if (end == null)
                                break;
                        }
                        pos = right + 1;
                    }
                    else
                    {
                        throw new Exception("error ()");

                    }
                }
                else
                {
                    throw new Exception("error ()");
                }

                left = NextBraceInLines(words, ref pos);
                if (left == "{")
                {//have 
                    var right = BraceEnd(words, pos - 1);
                    if (right < words.Count)
                    {
                        func.body = Body.Parse(words, pos, right);

                        pos = right + 1;

                    }
                    else
                    {
                        throw new Exception("error {}");

                    }
                }
                else
                {
                    throw new Exception("error {}");

                }
                return func;
            }
        }

        internal class Instruction : INode
        {
            public string opcode;
            public string retvalue;

            public Instruction if_condition;
            public string block_label;
            public Body block_body;
            public List<string> _params = new List<string>();
            public static Instruction Parse(IList<Word.Word> words, ref int pos)
            {
                var inst = new Instruction();
                var v1 = NextWordInLines(words, ref pos);
                var v2 = NextWordInLine(words, ref pos);
                List<string> nextv = new List<string>();
                var vn = NextWordInLine(words, ref pos);
                while (vn != null)
                {
                    if (vn != ",")
                        nextv.Add(vn);
                    vn = NextWordInLine(words, ref pos);
                }

                if (v2 == "=")
                {
                    inst.opcode = nextv[0];
                    inst.retvalue = v1;
                    for (var i = 1; i < nextv.Count; i++)
                    {
                        inst._params.Add(nextv[i]);
                    }
                }
                else
                {
                    inst.opcode = v1;
                    if (v2 != null)
                        inst._params.Add(v2);
                    for (var i = 0; i < nextv.Count; i++)
                    {
                        inst._params.Add(nextv[i]);
                    }
                }
                return inst;
            }
            public static Instruction ParseIf(IList<Word.Word> words, ref int pos)
            {
                var inst = new Instruction();
                inst.opcode = "if";
                var bs = AST.NextBraceInLines(words, ref pos);
                if (bs != "(")
                    throw new Exception("error if");
                inst.if_condition = Instruction.Parse(words, ref pos);
                var be = AST.NextBraceInLines(words, ref pos);
                if (be != ")")
                    throw new Exception("error if");

                if (AST.TryGetNextBraceInLines(words, ref pos, out string b))
                {
                    if (b == "{")
                    {
                        var right = BraceEnd(words, pos - 1);
                        inst.block_body = Body.Parse(words, pos, right);
                        pos = right + 1;
                        return inst;
                    }
                    //是一個body
                }

                var instsub = Instruction.Parse(words, ref pos);
                inst.block_body = new Body();
                inst.block_body.body.Add(instsub);
                return inst;

            }
            public static Instruction ParseBlock(IList<Word.Word> words, ref int pos)
            {
                var inst = new Instruction();
                inst.opcode = "block";

                if (AST.TryGetNextBraceInLines(words, ref pos, out string b))
                {
                    if (b == "{")
                    {
                        var right = BraceEnd(words, pos - 1);
                        inst.block_body = Body.Parse(words, pos, right);
                        pos = right + 1;
                        return inst;
                    }
                    //是一個body
                }

                var instsub = Instruction.Parse(words, ref pos);
                inst.block_body = new Body();
                inst.block_body.body.Add(instsub);
                return inst;
            }
        }

    }
}
